﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;

using Dapper;

using Jack.EntityFrameworkCore.WebAPITest.Entities;

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore.Storage;

namespace Jack.EntityFrameworkCore.WebAPITest.Controllers
{
    /// <summary>
    /// 商户余额
    /// </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class MerchantBalanceController : ControllerBase
    {
        private static readonly Random _random = new Random(Environment.TickCount);

        /// <summary>
        /// 初始化
        /// </summary>
        [HttpGet]
        public async Task<ActionResult<List<MerchantBalanceModel>>> Init([FromServices] IRepository<MerchantBalanceModel> merchantBalanceRepository, [FromServices] IUnitOfWork unitOfWork)
        {
            long merchantCode = 1;
            decimal balance = 999_999_999_999.9999m;

            List<MerchantBalanceModel> merchantBalanceModels = await merchantBalanceRepository.GetList(x => x.MerchantCode == merchantCode);
            if (merchantBalanceModels.Count > 0)
            {
                merchantBalanceModels.ForEach(item =>
                {
                    switch (item.AccountType)
                    {
                        case 1:
                            item.Balance = balance;
                            break;
                        case 2:
                            item.Balance = 0;
                            break;
                        default:
                            return;
                    }

                    merchantBalanceRepository.UpdatePartial(item, e => e.Balance);
                });
            }
            else
            {
                merchantBalanceModels.Add(new MerchantBalanceModel { MerchantCode = merchantCode, AccountType = 1, Balance = balance });
                merchantBalanceModels.Add(new MerchantBalanceModel { MerchantCode = merchantCode, AccountType = 2, Balance = 0 });
                await merchantBalanceRepository.InsertMany(merchantBalanceModels);
            }
            await unitOfWork.SaveChanges();

            return merchantBalanceModels;
        }

        /// <summary>
        /// 扣减额度
        /// </summary>
        [HttpGet]
        public async Task<ActionResult<object>> AbatementBalance_1([FromServices] IRepository<MerchantBalanceModel> merchantBalanceRepository, [FromServices] IUnitOfWork unitOfWork)
        {
            long merchantCode = 1;
            decimal amount = _random.Next(10, 10000) / 100m;
            decimal 授信额度 = 0;
            decimal 冻结额度 = 0;

            List<MerchantBalanceModel> merchantBalanceModels = await merchantBalanceRepository.GetList(x => x.MerchantCode == merchantCode);
            foreach (var merchantBalanceModel in merchantBalanceModels)
            {
                switch (merchantBalanceModel.AccountType)
                {
                    case 1:
                        授信额度 = merchantBalanceModel.Balance -= amount;
                        break;
                    case 2:
                        冻结额度 = merchantBalanceModel.Balance += amount;
                        break;
                    default:
                        continue;
                }

                merchantBalanceRepository.UpdatePartial(merchantBalanceModel, e => e.Balance);
            }
            await unitOfWork.SaveChanges();

            return new { 授信额度, 冻结额度, 扣减额度 = amount, 总额度 = 授信额度 + 冻结额度 };
        }

        /// <summary>
        /// 扣减额度
        /// </summary>
        [HttpGet]
        public async Task<ActionResult<object>> AbatementBalance_2([FromServices] IRepository<MerchantBalanceModel> merchantBalanceRepository, [FromServices] IUnitOfWork unitOfWork)
        {
            long merchantCode = 1;
            decimal amount = _random.Next(10, 10000) / 100m;
            decimal 授信额度 = 0;
            decimal 冻结额度 = 0;

            await using (var tran = await unitOfWork.BeginTransaction())
            {
                try
                {
                    List<MerchantBalanceModel> merchantBalanceModels = await merchantBalanceRepository.GetList(x => x.MerchantCode == merchantCode);
                    foreach (var merchantBalanceModel in merchantBalanceModels)
                    {
                        switch (merchantBalanceModel.AccountType)
                        {
                            case 1:
                                授信额度 = merchantBalanceModel.Balance -= amount;
                                break;
                            case 2:
                                冻结额度 = merchantBalanceModel.Balance += amount;
                                break;
                            default:
                                continue;
                        }

                        merchantBalanceRepository.UpdatePartial(merchantBalanceModel, e => e.Balance);
                    }
                    await unitOfWork.SaveChanges();
                    await tran.CommitAsync();
                }
                catch (Exception ex)
                {
                    await tran.RollbackAsync();
                    await Console.Out.WriteLineAsync(Convert.ToString(ex));
                    return BadRequest(ex);
                }
            }

            return new { 授信额度, 冻结额度, 扣减额度 = amount, 总额度 = 授信额度 + 冻结额度 };
        }

        /// <summary>
        /// 扣减额度
        /// </summary>
        [HttpGet]
        public async Task<ActionResult<object>> AbatementBalance_3([FromServices] IUnitOfWork unitOfWork)
        {
            long merchantCode = 1;
            decimal amount = _random.Next(10, 10000) / 100m;
            bool result = false;

            unitOfWork.TryOpen();
            using (var tran = unitOfWork.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
            {
                var dbDbTransaction = tran;
                try
                {
                    if (await unitOfWork.ExecuteAsync("UPDATE merchant_balance SET Balance = Balance - @Balance WHERE MerchantCode = @MerchantCode AND AccountType = @AccountType AND Balance > @Balance", new { Balance = amount, AccountType = 1, MerchantCode = merchantCode }, dbDbTransaction) == 1)
                    {
                        await unitOfWork.ExecuteAsync("UPDATE merchant_balance SET Balance = Balance + @Balance WHERE MerchantCode = @MerchantCode AND AccountType = @AccountType", new { Balance = amount, AccountType = 2, MerchantCode = merchantCode }, dbDbTransaction);
                        result = true;
                    }

                    //await unitOfWork.SaveChanges();
                    //await tran.CommitAsync();
                    dbDbTransaction.Commit();
                }
                catch (Exception ex)
                {
                    //await tran.RollbackAsync();
                    dbDbTransaction.Rollback();
                    await Console.Out.WriteLineAsync(Convert.ToString(ex));
                    return BadRequest(Convert.ToString(ex));
                }
            }

            return new { amount, result };
        }
    }
}
